/**
 * MCP客户端服务
 * MCP Client Service
 *
 * 功能说明:
 * - 创建和管理MCP(Model Context Protocol)客户端
 * - 连接飞书/LarkMCP服务器
 * - 提供工具调用功能
 *
 * Features:
 * - Create and manage MCP (Model Context Protocol) clients
 * - Connect to Lark MCP server
 * - Provide tool calling functionality
 */

import { experimental_createMCPClient as createMCPClient } from 'ai';
// @ts-ignore - 忽略类型检查，因为这是实验性功能
// @ts-ignore - Ignore type checking as this is experimental feature
import { Experimental_StdioMCPTransport as StdioMCPTransport } from 'ai/mcp-stdio';
import { config } from '../config/index.js';

/**
 * 通过 stdio 启动的 MCP 服务器定义
 * Definition for MCP servers started via stdio
 */
export interface StdioServerSpec {
  command: string;
  args?: string[];
  env?: Record<string, string>;
}
/**
 * MCP客户端服务类
 * MCP Client Service Class
 * 提供创建和管理MCP客户端的静态方法
 * Provides static methods for creating and managing MCP clients
 */
export class MCPClientService {
  /**
   * 创建飞书/LarkMCP客户端
   * Create Lark MCP client
   *
   * 该方法通过启动外部进程来创建MCP客户端连接
   * This method creates MCP client connection by starting external process
   *
   * @param accessToken 用户访问令牌（可选）/ User access token (optional)
   * @returns Promise<MCPClient> MCP客户端实例 / MCP client instance
   */
  static async createLarkMCPClient(accessToken?: string) {
    // 构建命令参数
    // Build command arguments
    let command = 'npx';
    let args = [
      '-y',
      '@larksuiteoapi/lark-mcp',
      'mcp',
      '-a',
      config.lark.appId,
      '-s',
      config.lark.appSecret,
      '-d',
      config.lark.domain,
      // 你可以自定义开启的 Tools 或者 Presets / You can custom enable tools or presets here
      // '-t',
      // 'bitable.v1.app.create,bitable.v1.appTable.create',
    ];

    // Use Windows platform to run npx command with cmd.exe | 使用 Windows 平台运行 npx 命令
    if (process.platform === 'win32') {
      args = ['/c', command, ...args];
      command = 'cmd.exe';
    }

    // 如果提供了用户访问令牌，添加到参数中
    // If user access token is provided, add it to arguments
    if (accessToken) {
      args.push('-u', accessToken);
      args.push('--token-mode', 'user_access_token');
    }

    // 创建并返回MCP客户端，使用标准输入输出传输
    // Create and return MCP client using stdio transport
    console.log('[MCP] 启动 Lark MCP 进程 / Launching Lark MCP process', { command, args });
    const client = createMCPClient({ transport: new StdioMCPTransport({ command, args }) });
    return client;
  }

  /**
   * 创建自定义 stdio MCP 客户端
   * Create custom stdio MCP client
   */
  static async createCustomMCPClient(spec: StdioServerSpec) {
    let command = spec.command;
    let args = spec.args || [];
    // Windows 平台使用 cmd.exe 包裹，确保命令可执行
    if (process.platform === 'win32') {
      args = ['/c', command, ...args];
      command = 'cmd.exe';
    }
    // @ts-ignore 允许 env 透传到底层进程
    console.log('[MCP] 启动自定义 stdio MCP 进程 / Launching custom stdio MCP process', { command, args, envKeys: Object.keys(spec.env || {}) });
    const client = createMCPClient({ transport: new StdioMCPTransport({ command, args, env: spec.env }) });
    return client;
  }
  
  /**
   * 使用 SSE 连接远程 MCP
   */
  static async createSseMCPClient(serverUrl: string) {
    // 直接使用动态导入，ESM 模式下不会被降级
    // Direct dynamic import - won't be downleveled in ESM mode
    console.log('[MCP] 连接远程 SSE MCP / Connecting remote SSE MCP', { url: serverUrl });
    // @ts-ignore - ESM 模块在编译时无法完全解析 / ESM modules cannot be fully resolved at compile time
    const sseMod = await import('@modelcontextprotocol/sdk/client/sse.js');
    // @ts-ignore
    const clientMod = await import('@modelcontextprotocol/sdk/client/index.js');

    const SSEClientTransport = (sseMod as any).SSEClientTransport;
    const MCPClient = (clientMod as any).Client;

    const client = new MCPClient({ name: 'app-mcp-client', version: '0.1.0' }, { capabilities: {} as any });
    const transport = new SSEClientTransport(new URL(serverUrl));
    await client.connect(transport);
    // 适配 AI SDK 期望的接口：tools() 和 close()
    const adapter = {
      async tools() {
        const res = await client.listTools();
        const tools: Record<string, { execute: (args: any) => Promise<any> }> = {};
        for (const tool of res.tools) {
          tools[tool.name] = {
            async execute(args: any) {
              const call = await client.callTool({ name: tool.name, arguments: args });
              return call;
            },
          };
        }
        return tools;
      },
      close() {
        client.close();
      },
    };
    return adapter as unknown as Awaited<ReturnType<typeof MCPClientService.createLarkMCPClient>>;
  }
}

/**
 * 一个最小可运行的 MCP 服务器（Node 版本，使用 @modelcontextprotocol/sdk）
 * Minimal runnable MCP server (Node, @modelcontextprotocol/sdk)
 * 
 * 用法（Windows）：
 *   node ./src/service/simple-mcp.js
 * 并在 .env 中配置：
 *   MCP_STDIO_SERVERS=[{"command":"node","args":["./src/service/simple-mcp.js"]}]
 */
